﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iOak.Business.Resumes;
using iOak.Business.Campaigns;
using iOak.Domain.ReportDomain;
using iOak.Domain.Campaigns;
using iOak.Domain.Resumes;
using System.Reflection;
using System.Linq.Expressions;

namespace iOak.Web.ExeclHelper
{
    public static class ExeclReportHelper
    {
        private static readonly ApplicationService itemApplicationService = new ApplicationService();
        private static readonly ApplicationCandidateService itemApplicationCandidateServic = new ApplicationCandidateService();
        private static readonly CampaignService itemCampaignService = new CampaignService();
        private static readonly CompanyService itemCompanyService = new CompanyService();
        private static readonly ResumeDetailService itemResumeDetailService = new ResumeDetailService();
        private static readonly ResumeService itemResumeService = new ResumeService();
        private static readonly PolicyService itemPolicyService = new PolicyService();
        private static readonly ResumeTemplateFieldsService itemResumeTemplateFieldsService = new ResumeTemplateFieldsService();        

        public static List<ResumeField> GetFiledList(Campaign itemCampaign)
        {
            // 根据campaignId获取模版ID
            var itemPolicy = itemPolicyService.Retrieve(itemCampaign.PolicyId);
            Guid templateId = itemPolicy.ResumeTemplateId;

            // 根据模版ID获取模版列表
            var listFiled = itemResumeTemplateFieldsService.GetReportField(templateId);

            return listFiled;
        }

        /// <summary>
        /// 转换生成execl数据
        /// </summary>
        /// <param name="itemCampaign"></param>
        /// <param name="listFiled"></param>
        /// <returns></returns>
        public static List<ExeclDetial> GetExeclData(Campaign itemCampaign, List<ResumeField> listFiled)
        {
            var returnList = new List<ExeclDetial>();

            // 获取Application 状态是 Checked的数据
            var listApplication = itemApplicationService.GetListByCampaignId(itemCampaign.CampaignId, true);

            // 获取候选人not null的数据
            var listApplicationCandidate = new List<ApplicationCandidate>();

            listApplication.ForEach(m =>
                {
                    listApplicationCandidate.AddRange(itemApplicationCandidateServic.GetPassedListByApplicationId(m.ApplicationId, true));
                });
            listApplicationCandidate = listApplicationCandidate.Distinct().ToList();

            // 反射获取动态加载方法类型
            var classType = typeof(ExeclReflectionHelper);
            var detialType = typeof(ExeclDetial);
            var listProperty = detialType.GetProperties().ToList();
            // 循环添加数据
            listApplicationCandidate.ForEach(item =>
              {
                  ExeclDetial addItem = new ExeclDetial();
                  // 取出动态数据
                  var listResumeDetail = itemResumeDetailService.GetListByResumeId(item.ResumeId);

                  listFiled.ForEach(fieldItem =>
                      {
                          string strValue = string.Empty;

                          // 通过动态数据加载
                          if (!string.IsNullOrWhiteSpace(fieldItem.ReportValue))
                          {
                              var itemValue = listResumeDetail.FirstOrDefault(m => m.Key.Equals(fieldItem.ReportValue));
                              if (itemValue != null)
                              {
                                  strValue = itemValue.ValueString;
                              }
                          }
                          else
                          {
                              // 通过方法动态加载
                              if (!string.IsNullOrWhiteSpace(fieldItem.LoadMethod))
                              {
                                  // 反射出方法
                                  var method = classType.GetMethod(fieldItem.LoadMethod, BindingFlags.Public | BindingFlags.Static);

                                  // 获取参数字段列表
                                  var strParame = Convert.ToString(fieldItem.LoadParameter).Split(',').Where(m => !string.IsNullOrWhiteSpace(m)).ToList();

                                  // 获取参数值
                                  object[] objValue = new object[strParame.Count + 2];
                                  for (int i = 0; i < strParame.Count; i++)
                                  {
                                      var itemParame = listResumeDetail.FirstOrDefault(m => m.Key.Equals(strParame[i]));
                                      if (itemParame != null)
                                      {
                                          objValue[i] = itemParame.ValueString;
                                      }
                                  }
                                  objValue[objValue.Length - 2] = item;
                                  objValue[objValue.Length - 1] = itemCampaign;

                                  strValue = method.Invoke(null, objValue) as string;
                              }
                          }
                          var itemProperty = listProperty.FirstOrDefault(m => m.Name.Equals("C" + fieldItem.ReportNumber));
                          itemProperty.SetValue(addItem, strValue, null);
                      });

                  // 添加统计信息 ----- 以后修改成动态
                  var itemCom = ExeclReflectionHelper.GetCompany(item);
                  addItem.BankName = itemCom.BankName;
                  addItem.Graduated = addItem.C8;
                  addItem.CompanyName = itemCom.CompanyName;
                  addItem.ContactPerson = itemCom.ContactPerson;
                  addItem.ContactPhone = itemCom.ContactPhone;
                  addItem.BankAccountNo = itemCom.BankAccountNo;
                  returnList.Add(addItem);
              });
            ExeclReflectionHelper.CompanyList.Clear();

            return returnList;
        }

        public static Dictionary<int, string> GetSumColList(List<ExeclDetial> listDetial, List<ResumeField> listFiled)
        {
            var listSum = listFiled.Where(m => m.IsSumField == true).Select(s =>
                new { s.ReportNumber, s.SumFormat });
            Dictionary<int, string> returnList = new Dictionary<int, string>();
            var sumList = listDetial.Where(m => m.C6.Equals("通过")).ToList();
            foreach (var item in listSum)
            {
                returnList.Add((int)item.ReportNumber, SumColList(sumList, "C" + item.ReportNumber, item.SumFormat));
            }
            return returnList;
        }

        /// <summary>
        /// 创建求和表达式
        /// </summary>
        /// <param name="listDetial"></param>
        /// <param name="colName"></param>
        /// <param name="sumFormat"></param>
        /// <returns></returns>
        public static string SumColList(List<ExeclDetial> listDetial, string colName, string sumFormat)
        {
            // 创建传入参数
            ParameterExpression input = Expression.Parameter(typeof(ExeclDetial), "item");

            // 转换对象为可执行表达式
            var queryableData = listDetial.AsQueryable<ExeclDetial>();

            // 获取对象类型
            var detialType = typeof(ExeclDetial);

            // 创建属性访问
            var protity = detialType.GetProperty(colName);

            // 创建访问属性的方法
            var parameterProtity = Expression.MakeMemberAccess(input, protity);

            // 创建类型转换
            var menth = typeof(Decimal).GetMethod("Parse", new Type[] { typeof(String) });
            Expression parameterBody = Expression.Call(null, menth, parameterProtity);
            
            // 创建Sum表达式
            Expression sumExpr = Expression.Call(
                    typeof(Queryable),
                    "Sum",
                    new Type[] { queryableData.ElementType },
                     queryableData.Expression,
                   Expression.Lambda<Func<ExeclDetial, decimal>>(parameterBody, new ParameterExpression[] { input }));

            // 求和
            var sum = queryableData.Provider.Execute<decimal>(sumExpr);

            // 返回
            return Math.Round(sum, Convert.ToInt32(sumFormat)).ToString();
        }

        /// <summary>
        /// 创建排序表达式
        /// </summary>
        /// <param name="listDetial"></param>
        /// <param name="listFiled"></param>
        /// <returns></returns>
        public static List<ExeclDetial> OrderByDataList(List<ExeclDetial> listDetial, List<ResumeField> listFiled)
        {
            List<int> numberList = listFiled.Where(m => m.ColDisplay != null).OrderBy(o =>
                o.ColDisplay).Select<ResumeField, int>(s => (int)s.ReportNumber).ToList<int>();

            // 创建传入参数
            ParameterExpression input = Expression.Parameter(typeof(ExeclDetial), "item");

            // 转换对象为可执行表达式
            var queryableData = listDetial.AsQueryable<ExeclDetial>();
            string strValue = string.Empty;
            string strMenthod = "OrderBy";
            Expression orderExpr = queryableData.Expression;

            // 获取对象类型
            var detialType = typeof(ExeclDetial);
            for (int i = 0; i < numberList.Count; i++)
            {
                strValue = "C" + numberList[i].ToString();

                // 获取当前属性
                var protity = detialType.GetProperty(strValue);

                // 创建访问属性的方法
                var parameterBody = Expression.MakeMemberAccess(input, protity);

                // 创建表达式树
                orderExpr = Expression.Call(
                    typeof(Queryable),
                    strMenthod,
                    new Type[] { queryableData.ElementType, typeof(string) },
                     orderExpr,
                   Expression.Lambda<Func<ExeclDetial, string>>(parameterBody, new ParameterExpression[] { input }));

                strMenthod = "ThenBy";
            }
            // 执行表达式树
            queryableData = queryableData.Provider.CreateQuery<ExeclDetial>(orderExpr);
            return queryableData.ToList();
        }
    }
}
